from fastapi import APIRouter, FastAPI, UploadFile, File, HTTPException, Body
from server.report.models.model import Scene, User, Report
from server.report.utils.mysql_utils import mysql_util 
from server.report.config.config import Config
from server.report.job.job import report_job
import os
import io
from server.report.schemas.item import ReportItem, UploadItem, ReportCancelItem
from datetime import timedelta, datetime
import math
import zipfile
from shlex import quote
from fastapi.responses import StreamingResponse
from sqlalchemy import and_

router = APIRouter(prefix='/report')


@router.get('/scene',tags=['report'])
def scene():
    with mysql_util.get_db() as db:
        scenes = db.query(Scene).all()
        res = []

        for scene in scenes:
            res.append({"id": scene.id, "scene": scene.scene})

        return res


@router.post('/upload',tags=['report'])
async def upload(item:UploadItem = Body(...), file: UploadFile = File(...)):
    cfg = Config()
    # 检查文件类型是否为 Word 文档
    if not file.filename.endswith(('.doc', '.docx', '.wps')):
        raise HTTPException(status_code=400, detail="仅支持 .doc, .docx 或 .wps 文件")

    item = item.data
    scene = item["scene"]
    report_name = item["report_name"]
    user_id = item["user_id"]

    # 创建上传目录
    os.makedirs(cfg.upload_dir, exist_ok=True)

    # 保存文件
    file_path = os.path.join(cfg.upload_dir, file.filename)

    content = await file.read()

    with open(file_path, "wb") as buffer:
        buffer.write(content)

    with mysql_util.get_db() as db:
        report = Report(report_name=report_name, scene=scene, user_id=user_id, input_file_path=file_path)
        mysql_util.db_add_commit_refresh(db, report)

        report_id = report.id

    # 添加到推理任务队列
    report_job.add_doc(report_id)

    return {"message": "文件上传成功", "file_path": file_path}


@router.post('/reports',tags=['report'])
async def reports(item: ReportItem):
    scene = item.scene
    report_name = item.report_name
    user_id = item.user_id
    start_date = item.start_date
    end_date = item.end_date
    page_index = item.page_index
    page_size = item.page_size

    filters = []

    if report_name:
        filters.append(Report.report_name.like(f"%{report_name}%"))

    if scene:
        filters.append(Report.scene.in_(scene))

    if start_date:
        filters.append(Report.start_date < end_date + timedelta(days=1))
        filters.append(Report.start_date >= start_date)

    if user_id:
        filters.append(Report.user_id == user_id)

    with mysql_util.get_db() as db:
        if filters:
            reports = db.query(Report).filter(and_(*filters))
        else:
            reports = db.query(Report)

        offset_data = page_size * (page_index-1)

        total_page = len(reports.all())
        reports = reports.order_by(Report.start_date.desc()).offset(offset_data).limit(page_size).all()

        res = []
        for report in reports:
            user = db.query(User).filter_by(id=report.user_id).first()
            generate_date = report.generate_date.strftime('%Y-%m-%d %H:%M:%S') if report.generate_date else report.generate_date
            res.append({"report_name": report.report_name, "scene": report.scene, "start_date": report.start_date.strftime('%Y-%m-%d %H:%M:%S'), "status": report.status, "department": user.department, "user_name": user.user_name, "email": user.email, "generate_date": generate_date, "report_id": report.id})

        return {"data": res, "total_page": total_page}


@router.post('/cancel',tags=['report'])
async def cancel(item: ReportCancelItem):
    report_id = item.report_id
    with mysql_util.get_db() as db:
        report = db.query(Report).filter_by(id=report_id).first()

        report.status = "CANCELLED"
        db.commit()

        return {"message": "取消成功", "code": 0}


@router.post('/download',tags=['report'])
async def download(item: ReportCancelItem):
    report_id = item.report_id

    with mysql_util.get_db() as db:
        report = db.query(Report).filter_by(id=report_id).first()
        input_file_path = report.input_file_path
        output_file_path = report.output_file_path
        report_name = report.report_name

    # 创建一个内存中的 ZIP 文件
    zip_buffer = io.BytesIO()

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    zip_name = f"{report_name}_{timestamp}.zip"
    
    with zipfile.ZipFile(zip_buffer, mode='w', compression=zipfile.ZIP_DEFLATED) as zip_file:
        # 添加一个示例文件到 ZIP 中
        os.chdir(os.path.dirname(input_file_path))
        zip_file.write(os.path.basename(input_file_path))
        os.chdir(os.path.dirname(output_file_path))
        zip_file.write(os.path.basename(output_file_path))

    # 将指针移到缓冲区开头
    zip_buffer.seek(0)

    # 定义 ZIP 文件名（支持中文）
    encoded_filename = quote(zip_name)

    # 构建响应头
    headers = {
        "Content-Disposition": f"attachment; filename={encoded_filename}; filename*=UTF-8''{encoded_filename}"
    }

    # 返回流式响应
    return StreamingResponse(
        content=zip_buffer,
        media_type="application/zip",
        headers=headers
    )